package cn.net.wanji.videoandetc.service;


import cn.net.wanji.videoandetc.pojo.FrameEtc;
import cn.net.wanji.videoandetc.pojo.FrameVideo;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xinyingjie
 * 策略1：基于特殊车型的时间对齐匹配方法
 * 原理：
 * 在车道中存在某些偶尔出现的特殊车型，例如大卡车或者大巴车，以特殊车型为标签进行对齐定位
 */
@Slf4j
public class CarTypeMethod {

    /**
     * 当特殊车型判断一致后，前后车型的判断时间阈值
     */
    public static final long TIMEPARA = 60*10;

    /**
     * 校验偏差最大阈值
     */
    public static final long PERTHREAD = (long) 0.1;
    /**
     * 普通车型
     */
    public static String CARTYPE = "car";


    /**
     * AI识别识别车辆队列，缓存固定时长（1小时）队列
     */
    public List<FrameVideo> videoList = new ArrayList<>();
    /**
     * ETC交易车辆队列，每固定周期（5分钟）批量加入队列
     * 缓存固定时长（1小时）队列
     */
    public List<FrameEtc> etcList = new ArrayList<>();


    private long method(List<FrameVideo> videoList, List<FrameEtc> etcList) {
        //存储最终的时间差
        long timeResult = 0;
        //队列非空判断
        if (videoList.size() == 0 || etcList.size() == 0) {
            log.error("存在某一队列为空，等待数据传入");
            return 0;
        }

        /**
         * 用于存放videoList中的特殊车型
         */
        Map<String, FrameVideo> videoMap = new LinkedHashMap<>();
        /**
         * 用于存放etcList中的特殊车型
         */
        Map<String, FrameEtc> etcMap = new LinkedHashMap<>();


        videoMap = saveVideoSpecialCar(videoList, videoMap);
        etcMap = saveEtcSpecialCar(etcList, etcMap);

        if (videoMap.isEmpty() || etcMap.isEmpty()) {
            log.error("两个队列中存在没有特殊车型的情况，策略失效");
            return 0;
        }
        List<FrameVideo> videoQueue = new ArrayList<>();
        List<FrameEtc> etcQueue = new ArrayList<>();

        for (String videoKey : videoMap.keySet()) {
            for (String etcKey : etcMap.keySet()) {
                FrameVideo frameVideo = videoMap.get(videoKey);
                FrameEtc frameEtc = etcMap.get(etcKey);

                boolean isSame = isSameCar(frameVideo, frameEtc);
                if (isSame){
                    int videoSize = BeforeAfterVideoSize(frameVideo.getTime(), videoQueue, videoMap);
                    int etcSize = BeforeAfterETCSize(frameEtc.getTime(),etcQueue,etcMap);
                    int per = Math.abs(videoSize - etcSize) / Math.max(videoSize, etcSize);
                    if (per <= PERTHREAD){
                        timeResult = frameVideo.getTime() - frameEtc.getTime();
                        break;
                    }
                }
            }
        }
        return timeResult;


    }

    /**
     * 计算ETC特殊车型前后固定时间的车辆数量
     * @param time
     * @param etcQueue
     * @param etcMap
     * @return
     */
    private int BeforeAfterETCSize(long time, List<FrameEtc> etcQueue, Map<String, FrameEtc> etcMap) {
        long beforeTime = time - TIMEPARA;
        long afterTime = time + TIMEPARA;
        for (String key : etcMap.keySet()) {
            long timeTemp = etcMap.get(key).getTime();
            if (timeTemp >= beforeTime && timeTemp <= afterTime){
                etcQueue.add(etcMap.get(key));
            }
        }
        return etcQueue.size();
    }

    /**
     * 计算视频检测特殊车型前后固定时间的车辆数量
     * @param time
     * @param videoQueue
     * @param videoMap
     * @return
     */
    private int BeforeAfterVideoSize(long time, List<FrameVideo> videoQueue, Map<String, FrameVideo> videoMap) {
        long beforeTime = time - TIMEPARA;
        long afterTime = time + TIMEPARA;
        for (String key : videoMap.keySet()) {
            long timeTemp = videoMap.get(key).getTime();
            if (timeTemp >= beforeTime && timeTemp <= afterTime){
                videoQueue.add(videoMap.get(key));
            }
        }
        return videoQueue.size();
    }


    /**
     * 判断两辆车是否为同一辆车，如果车型，颜色，车道号都一直，才认为是同一辆车
     * ETC车道号可能识别错误，但是为了严格保证识别的准确性，需要满足二者的车道号也一致
     *
     * @param frameVideo
     * @param frameEtc
     * @return
     */
    private boolean isSameCar(FrameVideo frameVideo, FrameEtc frameEtc) {
        int laneNum = frameVideo.getLaneNum();
        Map<String, Integer> colors = frameVideo.getColors();
        String carType = frameVideo.getCarType();
        int laneNum1 = frameEtc.getLaneNum();
        String color = frameEtc.getColor();
        String carType1 = frameEtc.getCarType();
        if (carType.equals(carType1) && laneNum == laneNum1 && colors.containsKey(color)) {
            return true;
        }
        return false;


    }

    /**
     * 顺序遍历etcList，如果车辆为特殊车型，将数据保存再etcMap中(key:carType value:FrameEtc)
     *
     * @param etcList
     * @param etcMap
     * @return
     */
    private Map<String, FrameEtc> saveEtcSpecialCar(List<FrameEtc> etcList, Map<String, FrameEtc> etcMap) {
        for (FrameEtc frameetc : etcList) {
            String carType = frameetc.getCarType();
            if (!carType.equals(CARTYPE)) {
                etcMap.put(carType, frameetc);
            }
        }
        return etcMap;
    }

    /**
     * 顺序遍历videoList，如果车辆为特殊车型，将数据保存再videoMap中(key:carType value:FrameVideo)
     *
     * @param videoList
     * @param videoMap
     * @return
     */
    private Map<String, FrameVideo> saveVideoSpecialCar(List<FrameVideo> videoList, Map<String, FrameVideo> videoMap) {
        for (FrameVideo frameVideo : videoList) {
            String carType = frameVideo.getCarType();
            if (!carType.equals(CARTYPE)) {
                videoMap.put(carType, frameVideo);
            }
        }
        return videoMap;
    }


}
